var child_process = require("node:child_process");
const { get_fst_file } = require("../utils/file_tool");
const { dirname } = require("node:path");
const { option } = require("yargs");

const iconv = require("iconv-lite");
const {
    info,
    warn,
    vital,
    error,
    whisper,
    success,
    log,
    isStdOut,
    setLastError,
    resetError,
} = require("../utils/log_tool");

/**
 *
 * @param {{ cmd: string | string[], cwd?: string, encoding?:string = "cp936", capture_stdout?: boolean = false, ignore_code?: boolean = false, shell?: boolean = false, inputs?: any[]}} data
 */
async function exec_shell(data) {
    const instant_stdout = data.instant_stdout;
    const capture_stdout = isStdOut() || data.capture_stdout;
    const acceptableErrors = data.acceptableErrors || [];
    const quiet = !data.verbose;
    const result = await new Promise((resolve, _reject) => {
        /** @type {string[]} */
        let cmd = data.cmd;
        if (typeof cmd === "string") {
            cmd = generateTokens(cmd);
        } else {
            cmd = cmd.map((v) => `${v}`);
        }
        let cwd = data.cwd;
        if (!cwd) {
            const filepath = get_fst_file(cmd);
            if (filepath) {
                cwd = dirname(filepath);
            }
        }
        if (cwd) {
            const exist = get_fst_file(cwd);
            if (!exist) {
                throw `未找到指定目录 ${cwd}`;
            } else {
                cwd = exist;
            }
        }
        const options = {
            cwd: cwd,
            // shell 为 false(默认值), 可能会影响后续的控制台打印
            // shell 为 true, 可能会影响 vbs 脚本调用
            shell: data.shell === undefined ? false : data.shell,
        };
        const results = [];
        const errors = [];
        const encoding = data.encoding || "cp936";
        const raw_output = encoding === "raw";
        !quiet && info(`cmd:[${cmd}] cwd:${data.cwd} inputs:${data.inputs}`);
        options.stdio = [
            "pipe",
            capture_stdout ? "pipe" : process.stdout,
            "pipe",
        ];
        const child = child_process.spawn(cmd[0], cmd.slice(1), options);
        if (child.stdout) {
            child.stdout.on("data", (chunk) => {
                results.push(chunk);
                if (instant_stdout) {
                    warn(
                        !raw_output
                            ? iconv.decode(chunk, encoding)
                            : chunk.toString(),
                    );
                }
            });
        }
        if (child.stderr) {
            child.stderr.on("data", (chunk) => {
                errors.push(chunk);
            });
        }
        try {
            if (child.stdin) {
                if (data.inputs) {
                    child.stdin.write(data.inputs.join("\n"));
                }
                child.stdin.end();
            }
        } catch (err) {
            setLastError(`${err}`);
            resolve("");
        }
        child.on("error", (err) => {
            setLastError(err);
            resolve("");
        });
        // child.on('close', code => {
        child.on("exit", (code) => {
            if (!data.ignore_code && code !== 0) {
                const errMsg = !raw_output
                    ? iconv.decode(Buffer.concat(errors), encoding)
                    : Buffer.concat(errors).toString();
                const isAcceptableErrors =
                    errMsg &&
                    acceptableErrors.some((err) => {
                        return errMsg.indexOf(err) >= 0;
                    });
                if (!isAcceptableErrors) {
                    setLastError(`错误码 ${code} ${errMsg}`, code);
                }
            }
            if (results.length) {
                let result = !raw_output
                    ? iconv.decode(Buffer.concat(results), encoding)
                    : Buffer.concat(results);
                if (data.trim) {
                    result = result.trim();
                }
                resolve(result);
            } else {
                resolve("");
            }
        });
    });
    if (!capture_stdout) {
        // 不捕获输出
        // 换行使打印数据显示更干净
        // log("");
    }
    return result;
}

/**
 * 解析字符串为token数组
 * @param {string} cmd
 * @returns
 */
function generateTokens(cmd) {
    const tokens = [];
    let buffer = "";
    for (let i = 0, len = cmd.length; i < len; ++i) {
        const char = cmd[i];
        if (buffer[0] === '"') {
            if (char === '"') {
                tokens.push(buffer.substring(1));
                buffer = "";
                continue;
            }
        } else {
            if (char === " ") {
                if (buffer.length) {
                    tokens.push(buffer);
                    buffer = "";
                }
                continue;
            }
        }
        buffer += char;
    }
    if (buffer.length) {
        tokens.push(buffer);
        buffer = "";
    }
    return tokens;
}

module.exports = {
    exec_shell,
};
